#include <sys/types.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <db.h>
#define DATABASE "free.db"
#define DBLOCATE "/home/liu/Berkeley_db_file"
using namespace std;

void print_error(int ret);
void init_DBT(DBT* key,DBT* data);
int db_insert(DB* dbp,int gc,char *gv[]);
int db_get(DB* dbp,int gc,char *gv[]);
int db_del(DB* dbp,int gc,char *gv[]);
int db_truncate(DB* dbp,int gc,char *gv[]);
int db_view(DB* dbp,int gc,char *gv[]);
timespec diff(timespec start,timespec end);

int main(int argc,char *argv[])
{
	if(1 == argc)
	{
		printf("argc error!\n");
		return 0;
	}
	timespec time_start,time_end;
	DB_ENV *myEnv;
	DB *dbp;
	int ret;
	u_int32_t env_flags;
	ret = db_env_create(&myEnv, 0);
	print_error(ret);
	env_flags = DB_CREATE | DB_INIT_MPOOL;
	ret = myEnv->open(myEnv,DBLOCATE,env_flags,0);
	print_error(ret);
	ret = db_create(&dbp,myEnv,0);
	print_error(ret);
	ret = dbp->open(dbp,NULL,DATABASE,NULL,DB_BTREE,DB_CREATE,0664);
	print_error(ret);
	//===================================
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&time_start);
	char c = *argv[1];
	switch(c)
	{
		case 'i':
			printf ("insert:\n");
			ret = db_insert(dbp,argc,argv);
			print_error(ret);
			break;
		case 'g':
			printf ("get:\n");
			ret = db_get(dbp,argc,argv);
			print_error(ret);
			break;
		case 'd':
			printf ("del:\n");
			ret = db_del(dbp,argc,argv);
			print_error(ret);
			break;
		case 't':
			printf ("truncate:\n");
			ret = db_truncate(dbp,argc,argv);
			print_error(ret);
			break;
		case 'v':
			printf ("view:\n");
			ret = db_view(dbp,argc,argv);
			break;
		default:
			printf ("option error!\n");
	}	
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&time_end);
	timespec time_used = diff(time_start,time_end);

	printf("%ld sec %ld nsecused!\n",time_used.tv_sec,time_used.tv_nsec);
	//================================
	if (dbp != NULL)
	{
		dbp->close(dbp, 0);
	}
	if (myEnv != NULL)
	{
		myEnv->close(myEnv, 0);
	}
	return 0;
}
void print_error(int ret)
{
	if(0 != ret)
	{
		printf("ERROR:%s\n",db_strerror(ret));
	}
}
void init_DBT(DBT* key,DBT* data)
{
	memset(key,0,sizeof(DBT));
	memset(data,0,sizeof(DBT));
}
int db_insert(DB* dbp,int gc,char *gv[])
{
	if(4 != gc)
	{
		printf("insert argc error!\n");
		return -1;
	}
	DBT key,data;
	init_DBT(&key,&data);
	int k = atoi(gv[2]);
	int d = atoi(gv[3]);
	key.size = sizeof(int);
	key.data = &k;
	data.size = sizeof(int);
	data.data =&d;
	//put data
	int ret = dbp->put(dbp,NULL,&key,&data,DB_NOOVERWRITE);
	return ret;
}
int db_get(DB* dbp,int gc,char *gv[])
{
	if(3 != gc)
	{
		printf("get argc error!\n");
		return -1;
	}
	DBT key,data;
	init_DBT(&key,&data);
	int tmp = atoi(gv[2]);
	key.size = sizeof(int);
	key.data = &tmp;
	int ret = dbp->get(dbp,NULL,&key,&data,0);
	if(NULL == data.data)
	{
		return ret;
	}
	int k = 0;
	int d = 0;
	memcpy(&k,key.data,sizeof(int));
	memcpy(&d,data.data,sizeof(int));
	printf("key = %d\t\t|data = %d\n",k,d);
	return ret;
}
int db_del(DB* dbp,int gc,char *gv[])
{
	DBT key,data;
	init_DBT(&key,&data);
	int tmp = atoi(gv[2]);
	key.size = sizeof(int);
	key.data = &tmp;
	int ret = dbp->del(dbp,NULL,&key,0);
	return ret;
}
int db_truncate(DB* dbp,int gc,char *gv[])
{
	DBT key,data;
	init_DBT(&key,&data);
	u_int32_t countp;
	int ret = dbp->truncate(dbp,NULL,&countp,0);
	return ret;
}
int db_view(DB* dbp,int gc,char *gv[])
{
	DBC *cur;

	DBT key,data;
	init_DBT(&key,&data);
	dbp->cursor(dbp,NULL,&cur,0);
	int ret = 0;
	while((ret = cur->c_get(cur,&key,&data,DB_NEXT)) == 0)
	{
		if(NULL == key.data || NULL == data.data)
		{
			continue;
		}
		int k = 0;
		memcpy(&k,key.data,sizeof(int));
		int d = 0;
		memcpy(&d,data.data,sizeof(int));
		printf("key = %d\t\t|data = %d\n",k,d);
	}
	cur->c_close(cur);
	return 0;
}
timespec diff(timespec start,timespec end)
{
	timespec temp;
	if((end.tv_nsec - start.tv_nsec) < 0)
	{
		temp.tv_sec = end.tv_sec - start.tv_sec - 1;
		temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
	}
	else
	{
		temp.tv_sec = end.tv_sec - start.tv_sec;
		temp.tv_nsec = end.tv_nsec - start.tv_nsec;
	}
	return temp;
}

